package net.ming616.nlp.ontology.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import net.ming616.nlp.ontology.model.DataUnit;
import net.ming616.nlp.ontology.service.RDFManager;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import com.hp.hpl.jena.query.Query;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QueryFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.Property;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.tdb.TDBFactory;

@Service("rdfManager")
public class RDFManagerImpl implements RDFManager {
	final String baseURI = "http://product/";

	/**
	 * Logger for this class
	 */
	@SuppressWarnings("unused")
	private final Logger logger = Logger.getLogger(RDFManagerImpl.class);

	Model model = null;

	public Resource addProperty(String resourceName, String propertyName,
			String propertyValue) {
		if (null == this.model) {
			this.generateModel();
		}
		Resource resource = this.model.getResource(baseURI + resourceName);
		if (null == resource) {
			resource = this.model.createResource(baseURI + resourceName);
		}
		Property property = this.model.getProperty(baseURI + propertyName);
		if (null == property) {
			property = this.model.createProperty(baseURI, propertyName);
		}
		resource.addProperty(property, propertyValue);
		this.model.commit();
		return resource;
	}

	public List<DataUnit> findByObject(String obj) {
		String sparqlQueryString = "";
		StringBuffer buffer = new StringBuffer();
		buffer.append(" PREFIX resource: <" + this.baseURI + ">");
		buffer.append(" SELECT ?subj ?relation ?obj");
		buffer.append(" WHERE {");
		buffer.append(" ?subj ?relation" + " \"" + obj + "\" . ");
		buffer.append(" }");
		sparqlQueryString = buffer.toString();
		List<DataUnit> result = this.query(sparqlQueryString);
		for (DataUnit du : result) {
			if (du.getObject() == null) {
				du.setObject(obj);
			}
		}
		return result;
	}

	public List<DataUnit> findBySubject(String subject) {
		String sparqlQueryString = "";
		StringBuffer buffer = new StringBuffer();
		buffer.append(" PREFIX resource: <" + this.baseURI + ">");
		buffer.append(" SELECT ?subj ?relation ?obj");
		buffer.append(" WHERE {");
		buffer.append("resource:" + subject + " ?relation ?obj . ");
		buffer.append(" }");
		sparqlQueryString = buffer.toString();
		List<DataUnit> result = this.query(sparqlQueryString);
		for (DataUnit du : result) {
			if (du.getSubject() == null) {
				du.setSubject(subject);
			}
		}
		return result;
	}

	@PostConstruct
	void generateModel() {
		// Create an empty Model
		String directory = "d:/ming616/test/ontology/";
		this.model = TDBFactory.createModel(directory);
	}

	public Resource generateResource(String resourceName) {
		Resource resource = this.model.createResource(this.baseURI
				+ resourceName);
		return resource;
	}

	private List<DataUnit> query(String sparqlQueryString) {
		List<DataUnit> result = new ArrayList<DataUnit>();
		Query query = QueryFactory.create(sparqlQueryString);
		QueryExecution qexec = QueryExecutionFactory.create(query, this.model);
		ResultSet queryResults = qexec.execSelect();

		while (queryResults.hasNext()) {
			DataUnit dataUnit = new DataUnit();
			QuerySolution soln = queryResults.next();
			String subj = null, relation = null, obj = null;
			if (soln.contains("?subj")) {
				subj = model.getResource(soln.get("subj").toString())
						.getLocalName();
			}
			if (soln.contains("?relation")) {
				relation = model.getResource(soln.get("relation").toString())
						.getLocalName();
			}
			if (soln.contains("?obj")) {
				RDFNode node = soln.get("obj");
				obj = node.toString();
			}
			dataUnit.setSubject(subj);
			dataUnit.setRelation(relation);
			dataUnit.setObject(obj);
			result.add(dataUnit);
		}
		qexec.close();
		return result;
	}

}
